/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2010 huliqing, huliqing.cn@gmail.com
 *
 * This file is part of QFaces.
 * QFaces is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * QFaces is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with QFaces.  If not, see <http://www.gnu.org/licenses/>.
 *
 * 这个文件是QFaces的一部分。
 * 您可以单独使用或分发这个文件，但请不要移除这个头部声明信息.
 * QFaces是一个自由软件，您可以自由分发、修改其中的源代码或者重新发布它，
 * 新的任何修改后的重新发布版必须同样在遵守LGPL3或更后续的版本协议下发布.
 * 关于LGPL协议的细则请参考COPYING、COPYING.LESSER文件，
 * 您可以在QFaces的相关目录中获得LGPL协议的副本，
 * 如果没有找到，请连接到 http://www.gnu.org/licenses/ 查看并获取副本。
 *
 * - Author: Huliqing
 * - Contact: huliqing.cn@gmail.com
 * - License: GNU Lesser General Public License (LGPL)
 * - Blog and source code availability: http://www.huliqing.name/
 */


Q.F.UILinkage = {
	linkages : new Array(),
	init : function (clientId, componentClass, targetIds, listenerExp, isPostBack, isDefaultValue) {
		if (this.linkages[clientId] == null)
			this.linkages[clientId] = new Q.F.Linkage(clientId, componentClass, targetIds, listenerExp, isPostBack, isDefaultValue);
	}
}

Q.F.Linkage = function(clientId, componentClass, targetIds, listenerExp, isPostBack, isDefaultValue) {
	this.clientId = clientId;
	this.componentClass = componentClass;
	this.targetIds = targetIds;
	this.listenerExp = listenerExp;
	this.isPostBack = (isPostBack == "true" ? true : false);
	// 如果这是一个修改操作，那么isDefaultValue将会是true,这时需要为默认值添加正确的初始下拉option
	this.isDefaultValue = (isDefaultValue == "true" ? true : false);
	// 选项节点的根节点,root为一个树形结构，包含了所有可能的选项
	this.root = new Q.F.Linkage.Node(null, null);
	// rootSelectObj控件，一个链表结构，从nextSelect中或得下一级的select组件
	this.selectObj = new Q.F.Linkage.SelectObj();
	this.init = function() {
		// 初始化select链表,将for所指定的各个select控件链接起来
		this.selectObj.init(this.targetIds, 0, null);
		
		// 初始化root,将第一层级的option存入root节点中
		var options = this.selectObj.select.options;
		if (options != null && options.length != 0) {
			for (var i = 0; i < options.length; i++) {
				var node = new Q.F.Linkage.Node(options[i].value, options[i].text);
				this.root.add(node);
			}
		}
		// 载入select的事件响应
		this.selectObj.initEvent(this.selectObj, this);
		// 如果是有默认值的修改
		if (this.isDefaultValue) {
			Q.debug("start to init default Value...")
			this.initDefaultValue(this, this.selectObj);
		} else {
			// 如果没有任何默认值（第一个select框没有内容、NULL），那么应该清理下级的options.
			// 否则在回传请求的情况下，可能因为用户取消了第一个select的选择，但是下级的select的
			// option可能存在不匹配的options（这是上一个请求遗留下来的）,
			if (this.selectObj.nextSelectObj != null) {
				this.selectObj.nextSelectObj.clear();
			}
		}
	}
	// 找出当前currentSelectObj.select的值所对应的root节点中的node
	this.findNodeBySelectValue = function(rootNode, rootSelectObj, targetSelectObj) {
		var _currNode = rootNode;
		var _currSelectObj = rootSelectObj;
		while (_currSelectObj.level <= targetSelectObj.level) {
			_currNode = _currNode.find(_currSelectObj.select.value);
			if (_currSelectObj.nextSelectObj == null) 
				break;
			_currSelectObj = _currSelectObj.nextSelectObj;
		}
		return _currNode;
	}
	// 通过targetId(select控件的id)，查找链表中对应的selectObj
	this.findSelectObjByTargetId = function(_self, targetId) {
		var currentObj = _self.selectObj;
		while (currentObj != null) {
			if (currentObj.select.id == targetId) {
				break;
			}
			currentObj = currentObj.nextSelectObj;
		}
		return currentObj;
	}
	// 能过select的初次载入时的value去获取下一次的option
	this.initDefaultValue = function(_self, currentSelectObj) {
		// 如果select本身没有默认值，那么不需要这个载入defaultValue的过程,
		// 与autoInitValue不同，initDefaultValue时，currentSelectObj.select.value应该为null或空
		// 所以不要直接去调用autoInitValue.
		if (currentSelectObj.defaultValue == null || currentSelectObj.defaultValue == "") {
			Q.debug("The defaultValue not found, process end.");
			return;
		}
		Q.debug("Start request options for default value:" + currentSelectObj.defaultValue);
		_self.processChange(_self, currentSelectObj);
	}
	// 用于联动载入select的下级options
	this.autoInitValue = function(_self, currentSelectObj) {
		// 如果onchange后，当前触发的select的value为"",那么不需要调用Ajax请求，但需要清理下级select的options
		if (currentSelectObj.select.value == "") {
			Q.debug("No value selected, clear next options if exist and then return:" + currentSelectObj.select.id);
			if (currentSelectObj.nextSelectObj != null) {
				Q.debug("Clear next options." + currentSelectObj.nextSelectObj.select.id);
				currentSelectObj.nextSelectObj.clear();
			}
			return;
		}
		Q.debug("CurrentSelectObj's value not null, auto request next options start:" + currentSelectObj.select.id);
		_self.processChange(_self, currentSelectObj);
	}
	// Event,select的响应动用(默认：onchange),不要使用this.autoInitValue
	this.changeListener = function(targetId) {
		var currentSelectObj = this.findSelectObjByTargetId(this, targetId);
		this.processChange(this, currentSelectObj);
	}
	this.processChange = function(_self, currentSelectObj) {
		// 如果已经没有下一级，那就没有必要再请求值了
		if (currentSelectObj.nextSelectObj == null) {
			Q.debug("No next select obj, will return." + currentSelectObj.select.id);
			return;
		}
		// 链式清理下一级的select下的options内容,准备重置,当select发生onchange之后第一时间就应该clear下级的options
		currentSelectObj.nextSelectObj.clear();
		// 找出当前触发的select所对应的存在于root中的节点
		var currentSelectNode = _self.findNodeBySelectValue(_self.root, _self.selectObj, currentSelectObj);
		
		if (!currentSelectNode.loaded) {
			Q.debug("CurrentSelectNode has not load options for next,ready to request by ajax." + currentSelectObj.select.id);
			var ajax = Q.F.Ajax.build(_self.clientId);
		    ajax.put("componentClass", _self.componentClass);
		    ajax.put("listenerExp", _self.listenerExp);
		    ajax.put("levelCount", (currentSelectObj.level + 1));
		    var currentLevel = currentSelectObj.level;
		    var selectObj = currentSelectObj;
		    while (currentLevel >= 0) {
			    ajax.put("level_" + selectObj.level, selectObj.select.value);
			    selectObj = selectObj.previousSelectObj;
			    currentLevel -= 1;
		    }
		    
		    var process = function () {
		    	// 取得回传数据并处理成option数组
		    	var resultOfNodes = _self.makeNodesByResult(ajax.request.responseXML);
		    	var resultOfText = ajax.request.responseText;
		    	// 保存nodes到currentSelectNode中，并且要保存返回的text形式的数据(for layz=true)
		    	// 作为其它子节点(并将节点状态设为loaded=true)下次将不用ajax请求(很重要)
		    	for (var x = 0; x < resultOfNodes.length; x++) {
		    		currentSelectNode.add(resultOfNodes[x]);
		    	}
		    	currentSelectNode.childText = resultOfText;
		    	currentSelectNode.loaded = true;
		    	// 设置下一select的子选项，同时需要设置对应的隐藏框的数据
		    	Q.debug("Set next options for " + currentSelectObj.nextSelectObj.select.id);
		        _self.setChilds(currentSelectObj.nextSelectObj.select, resultOfNodes);
		        currentSelectObj.nextSelectObj.hiddenOptions.value = resultOfText;
		        // 如果存在默认设置的值，即可能为第一次打开修改界面时
		        if (_self.isDefaultValue) {
		        	if (currentSelectObj.nextSelectObj.defaultValue != null && 
		        			!currentSelectObj.nextSelectObj.hasDefaultValueSet) {
		        		currentSelectObj.nextSelectObj.select.value = currentSelectObj.nextSelectObj.defaultValue;
		        		currentSelectObj.nextSelectObj.hasDefaultValueSet = true;
		        		// 进行下一级的默认值载入
		        		Q.debug("Go to next for default value set:" + currentSelectObj.nextSelectObj.select.id);
		        		Q.U.setTimeout(_self.initDefaultValue, 20, _self, currentSelectObj.nextSelectObj);
		        	} else {
		        		// 正常联动载入下一级,在set default value之后
			        	Q.debug("Ready to auto init next(after default value init):" + currentSelectObj.nextSelectObj.select.id);
			        	Q.U.setTimeout(_self.autoInitValue, 20, _self, currentSelectObj.nextSelectObj);
		        	}
		        } else {
		        	// 正常联动载入下一级
		        	Q.debug("Ready to auto init next:" + currentSelectObj.nextSelectObj.select.id);
		        	Q.U.setTimeout(_self.autoInitValue, 20, _self, currentSelectObj.nextSelectObj);
		        }
		    }
		    ajax.setProcess(process);
		    ajax.get();
		} else {
			Q.debug("CurrentSelectNode has loaded options for next, don't need to request." + currentSelectObj.select.id);
			_self.setChilds(currentSelectObj.nextSelectObj.select, currentSelectNode.childNodes);
			currentSelectObj.nextSelectObj.hiddenOptions.value = currentSelectNode.childText; // 在layz模式时用到了childText数据
			// 载入下级
			Q.U.setTimeout(_self.autoInitValue, 20, _self, currentSelectObj.nextSelectObj);
		}
	}
	
	//----------------------------
	
	this.makeNodesByResult = function(responseXML) {
		var nodes = new Array();
	    var items = responseXML.documentElement;
	    var itemList = null;
	    if (items != null) {
	        itemList = items.getElementsByTagName("item");
	    }
	    if (itemList != null) {
	        for (var i = 0; i < itemList.length; i++) {
	            var item = itemList[i];
	            var node = new Q.F.Linkage.Node(item.getAttribute("value"), item.getAttribute("label"));
	            nodes[i] = node;
	        }
	    }
	    return nodes;
	}
	// 设置select的option值
	this.setChilds = function(target, nodes) {
		Q.debug("nodes.length=" + nodes.length);
	    for (var i = 0; i < nodes.length; i++) {
	    	var opt = new Option();
	    	opt.value = nodes[i].value;
	    	opt.text = nodes[i].text;
	        target.options.add(opt);
	    }
	}
	// init
	this.init();
}
Q.F.Linkage.SelectObj = function() {
	this.level = -1;
	this.select = null;				// 所绑定的select组件
	this.hiddenOptions = null;		// 保存当前select的选项列表的hidden组件(input), xml格式
	this.previousSelectObj = null;	// 链表的上一个selectObj
	this.nextSelectObj = null;		// 链表的下一个selectObj
	
	// 当Linkage的defaultValue不为null并且未set时，表示正在进行修改操作，那么当界面载入时，select有默认值
	// 这时候需要从第level 0 开始一级一级载入select控件的默认值,及初始化它们的下拉框选项
	this.hasDefaultValueSet = false;
	this.defaultValue = null;

	// targetIds 格式为： id1,id2,id3,id4
	// 把几个select控件链接起来.
	// level: 当前级别， previousSelectObj:上一级select
	this.init = function(targetIds, level, previousSelectObj) {
		var id = null;
		var lastIds = null;
		if (targetIds.indexOf(",") != -1) {
			id = targetIds.substring(0, targetIds.indexOf(","));
			lastIds = targetIds.substring(targetIds.indexOf(",") + 1);
		} else {
			id = targetIds;
		}
		this.initComponent(this, level, id, lastIds, previousSelectObj);
	}
	this.initComponent = function(_self, level, id, lastIds, previousSelectObj) {
		var obj = Q.get(id);
		var defaultValueObj = Q.get(id + ":defaultValue"); // 获取可能存在的默认值
		var hiddenFieldObj = Q.get(id + ":hiddenValue");	 // 隐藏的下拉选项值
		if (obj != null) {
			// 装载并初始化当前select的值
			_self.level = parseInt(level, 10);
			_self.select = obj;
			_self.previousSelectObj = previousSelectObj;
			if (defaultValueObj != null && defaultValueObj.value != "")
				this.defaultValue = defaultValueObj.value;
			if (hiddenFieldObj != null)
				this.hiddenOptions = hiddenFieldObj;
			// 进行下一级的初始化
			if (lastIds != null && lastIds != "") {
				_self.nextSelectObj = new Q.F.Linkage.SelectObj();
				_self.nextSelectObj.init(lastIds, (_self.level + 1), _self);
			}
		} else { // 确保每个select都能够找到
			Q.U.setTimeout(_self.initComponent, 20, _self, level, id, lastIds, previousSelectObj);
		}
	}
	this.initEvent = function(_self, linkage) {
		Q.U.attachEvent(_self.select.id, "onchange", function(){linkage.changeListener(_self.select.id);});
		if (_self.nextSelectObj != null) {
			_self.nextSelectObj.initEvent(_self.nextSelectObj, linkage);
		}
	}
	this.clear = function() {
		if (this.select == null) return;
		while (this.select.hasChildNodes()) {
			this.select.removeChild(this.select.firstChild);
		}
		if (this.nextSelectObj != null)
			this.nextSelectObj.clear();
	}
}
Q.F.Linkage.Node = function(value, text) {
	this.value = value;
	this.text = text;
	// 这表示是否已经装载过一次数据，如果装载过，那么下次将不再进行ajax请求
	this.loaded = false;
	// 用于保存通过Ajax回传回来的数据，即下一级的选项列表的数据，该数据是一个XML格式的字符串.
	// 保存这个数据主要在于懒惰模式时，不进行重新Ajax请求，而hiddenValue域需要保存select框
	// 对应的下拉选项的数据，这些数据需要一同提交回后台分析，而实际的select的下拉选项并不提交。
	// 所以依靠对应的hiddenValue域保存，并提交相关数据。
	// <items>
    //      <item value="" label="" />
    //      <item value="" label="" />
    // </items>
	this.childText = "";
	// Children,这个非数组类型,在add到target之时无法使用length属性（no use)
	this.children = new Array();
	// 数组类型，有length属性
	this.childNodes = new Array();
	// Add a child node
	this.add = function(child) {
		this.children[child.value] = child;
		if (this.childNodes.length == 0) {
			this.childNodes[0] = child;
		} else {
			this.childNodes[this.childNodes.length] = child;
		}
	}
	// Find child node by node.value
	this.find = function(value) {
		return this.children[value];
	}
}